package com.library.ble;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.library.ble.conn.BleCallback;
import com.library.ble.conn.BleDataConnector;
import com.library.ble.exception.BleException;
import com.library.ble.exception.ConnectException;
import com.library.ble.impl.callback.BleGattCallback;
import com.library.ble.impl.scan.PeriodMacScanCallback;
import com.library.ble.impl.scan.PeriodScanCallback;
import com.library.ble.utils.LogUtil;


import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;


/**
 * Created by gongjianghua on 16/3/2.
 */
public class BleDeviceManager {


    private static final String TAG = BleDeviceManager.class.getSimpleName();

    /** 开启gps 6.0以上则需要开启这个权限*/
    public static final int TO_OPEN_GPS=1212;

    /** 已断开连接*/
    public static final int STATE_DISCONNECTED  = 1;
    /** 正在连接中 */
    public static final int STATE_CONNECTING    = 2;
    /** 已连接*/
    public static final int STATE_CONNECTED     = 3;

    /** 正在扫描 */
    public static final int STATE_SCANNING      = 0;
    /** 服务已经搜索 */
    public static final int STATE_SERVICES_DISCOVERED = 5;


    private BluetoothAdapter bluetoothAdapter;
    private BluetoothGatt bluetoothGatt;
    private BluetoothManager bluetoothManager;
    private Set<BluetoothGattCallback> callbackList = new CopyOnWriteArraySet<>();
    private int connectionState = STATE_DISCONNECTED;
    private Context context;

    private Handler mHanlder=null;

    /** 当前正在扫描的蓝牙回调 */
    private BluetoothAdapter.LeScanCallback scanCallBack=null;

    /** 6.0中需要判断的权限 */
    public static final String[] SCAN_BLE_PERMISSIONS=new String[]{
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION,
    };

    /** 硬件是否支持蓝牙 false为不支持，true为支持 */
    private boolean hardwareSupport=true;
    /** 系统是否支持蓝牙4.0 false为不支持，true为支持 */
    private boolean systemSupport=true;




    public BleDeviceManager(Context context) {
        this.context = context;
        this.mHanlder=new MyHanlder(context.getMainLooper());
        checkBleEnable();
    }

    /**
     * 蓝牙初始化，同时检查蓝牙情况
     */
    public void checkBleEnable() {
        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            hardwareSupport=false;
            return;
        }
        bluetoothManager=
                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();
        if (bluetoothAdapter == null) {
            systemSupport = false;
            return;
        }
    }

    /**
     * 获取检查系统的情况
     * @return  true为手机支持蓝牙4。0，false则为手机完全不支持
     */
    public boolean getSupprotForPhone(){
        return  hardwareSupport&&systemSupport;
    }


    /**
     * 返回当前蓝牙是否打开
     * @return
     */
    public boolean isOpenBle(){
        return this.bluetoothAdapter.isEnabled();
    }

    /**
     * 是否正在扫描
     * @return
     */
    public boolean isInScanning() {
        return this.connectionState == STATE_SCANNING;
    }

    /**
     * 是否正在连接或者已经连接上设备了
     * @return
     */
    public boolean isConnectingOrConnected() {
        return this.connectionState >= STATE_CONNECTING;
    }
    /**
     * 是否已经连接设备了
     * @return
     */
    public boolean isConnected() {
        return this.connectionState >= STATE_CONNECTED;
    }

    /**
     * 是否正在发现设备了
     * @return
     */
    public boolean isServiceDiscoered() {
        return this.connectionState == STATE_SERVICES_DISCOVERED;
    }


    public boolean addGattCallback(BluetoothGattCallback callback) {
        return this.callbackList.add(callback);
    }

    public boolean addGattCallback(BleGattCallback callback) {
        return this.callbackList.add(callback);
    }


    public boolean removeGattCallback(BluetoothGattCallback callback) {
           return this.callbackList.remove(callback);
    }


    /**
     * 扫描设备 全部设备
     * @param callback
     * @return
     */
    public boolean startLeScan(PeriodScanCallback callback) {
        if(isInScanning()){
            return true;
        }
        callback.notifyScanStarted();
        boolean suc = this.bluetoothAdapter.startLeScan(callback);
        if (suc) {
            scanCallBack=callback;
            this.connectionState = STATE_SCANNING;
        } else {
            callback.removeHandlerMsg();
        }
        return suc;
    }

    /**
     * 扫描指定设备的
     * @param callback
     */
    public void startLeScanForMac(PeriodMacScanCallback callback) {
        startLeScan(callback);
    }

    /**
     * 停止扫描和连接操作
     */
    public void stopScan() {
        if(scanCallBack!=null){
            stopScan(scanCallBack);
        }
    }

    /**
     * 停止扫描
     * @param callback
     */
    public void stopScan(BluetoothAdapter.LeScanCallback callback) {
        if (callback instanceof PeriodScanCallback) {
            ((PeriodScanCallback) callback).removeHandlerMsg();
        }
        this.bluetoothAdapter.stopLeScan(callback);
        if (this.connectionState == STATE_SCANNING) {
            this.connectionState = STATE_DISCONNECTED;
            scanCallBack=null;
        }
    }


    /**
     * 总的蓝牙回调处理
     */
    public BleGattCallback coreGattCallback=new BleGattCallback() {
        @Override
        public void onConnectFailure(BleException bleException) {
            BleDeviceManager.this.bluetoothGatt=null;
            for (BluetoothGattCallback callback: callbackList) {
                if(callback instanceof BleGattCallback){
                    ((BleGattCallback)callback).onConnectFailure(bleException);
                }
            }
        }

        @Override
        public void onConnectSuccess(BluetoothGatt bluetoothGatt, int state) {
            BleDeviceManager.this.bluetoothGatt=bluetoothGatt;
            for (BluetoothGattCallback callback: callbackList) {
                if(callback instanceof BleGattCallback){
                    ((BleGattCallback)callback).onConnectSuccess(bluetoothGatt, state);
                }
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt bluetoothGatt, int state) {
            BleDeviceManager.this.connectionState = BleDeviceManager.STATE_SERVICES_DISCOVERED;
            for (BluetoothGattCallback call :callbackList) {
                call.onServicesDiscovered(bluetoothGatt, state);
            }
        }

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            LogUtil.d(TAG, "onConnectionStateChange  status: " + status + " ,newState: " + newState + "  ,thread: " + Thread.currentThread().getId());
            if(status== BluetoothGatt.GATT_SUCCESS){//通信成功
                if (newState == BluetoothGatt.STATE_CONNECTED) {
                    BleDeviceManager.this.connectionState = BleDeviceManager.STATE_CONNECTED;
                    onConnectSuccess(gatt, status);
                } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
                    BleDeviceManager.this.connectionState = BleDeviceManager.STATE_DISCONNECTED;
                    onConnectFailure(new ConnectException(gatt, status));
                } else if (newState == BluetoothGatt.STATE_CONNECTING) {
                    BleDeviceManager.this.connectionState = BleDeviceManager.STATE_CONNECTING;
                }
            }else{
                BleDeviceManager.this.connectionState = BleDeviceManager.STATE_DISCONNECTED;
                onConnectFailure(new ConnectException(gatt, status));
            }
            if(BleDeviceManager.this.callbackList.size()>0) {
                for (BluetoothGattCallback call : BleDeviceManager.this.callbackList) {
                    call.onConnectionStateChange(gatt, status, newState);
                }
            }
        }


        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            if(BleDeviceManager.this.callbackList.size()>0) {
                for (BluetoothGattCallback call : BleDeviceManager.this.callbackList) {
                    call.onCharacteristicRead(gatt, characteristic, status);
                }
            }
        }

        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            if(BleDeviceManager.this.callbackList.size()>0) {
                for (BluetoothGattCallback call : BleDeviceManager.this.callbackList) {
                    call.onCharacteristicWrite(gatt, characteristic, status);
                }
            }
        }

        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            if(BleDeviceManager.this.callbackList.size()>0) {
                for (BluetoothGattCallback call : BleDeviceManager.this.callbackList) {
                    call.onCharacteristicChanged(gatt, characteristic);
                }
            }
        }

        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            if(BleDeviceManager.this.callbackList.size()>0) {
                for (BluetoothGattCallback call : BleDeviceManager.this.callbackList) {
                    call.onDescriptorRead(gatt, descriptor, status);
                }
            }
        }

        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            if(BleDeviceManager.this.callbackList.size()>0) {
                for (BluetoothGattCallback call : BleDeviceManager.this.callbackList) {
                    call.onDescriptorWrite(gatt, descriptor, status);
                }
            }
        }

        public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
            if(BleDeviceManager.this.callbackList.size()>0) {
                for (BluetoothGattCallback call : BleDeviceManager.this.callbackList) {
                    call.onReliableWriteCompleted(gatt, status);
                }
            }
        }

        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            if(BleDeviceManager.this.callbackList.size()>0) {
                for (BluetoothGattCallback call : BleDeviceManager.this.callbackList) {
                    call.onReadRemoteRssi(gatt, rssi, status);
                }
            }
        }
        


    };


    /**
     * 连接设备
     * @param device 设备
     * @param autoConnect
     * @param callback
     * @return
     */
    public synchronized BluetoothGatt connect(BluetoothDevice device, boolean autoConnect, BleGattCallback callback) {
        LogUtil.d(TAG, "connect device\uff1a" + device.getName() + " mac:" + device.getAddress() + " autoConnect ------> " + autoConnect);
        this.callbackList.add(callback);
        return device.connectGatt(this.context, autoConnect, this.coreGattCallback);
    }

//    public boolean refreshDeviceCache() {
//        try {
//            Method refresh = BluetoothGatt.class.getMethod("refresh", new Class[STATE_DISCONNECTED]);
//            if (refresh != null) {
//                boolean success=false;
//                if(this.bluetoothGatt!=null) {
//                     success = ((Boolean) refresh.invoke(bluetoothGatt, new Object[STATE_DISCONNECTED])).booleanValue();
//                }
//                Log.i(TAG, "Refreshing result: " + success);
//                return success;
//            }
//        } catch (Exception e) {
//            Log.e(TAG, "An exception occured while refreshing device", e);
//        }
//        return false;
//    }
    /**
     * 关闭设备连接
     */
    public void closeBluetoothGatt() {
        if(this.bluetoothGatt != null) this.bluetoothGatt.disconnect();
        if(this.bluetoothGatt != null) this.bluetoothGatt.close();
        if(bleDataConnector!=null){
            bleDataConnector.closeHandler();
            bleDataConnector=null;
        }
        Log.i(TAG, "closed BluetoothGatt ");
    }

    /**
     *  扫描设备并且自动连接上去
     * @param mac 地址
     * @param autoConnect
     * @param callback
     * @return
     */
    public boolean scanAndConnect(String mac, boolean autoConnect, BleGattCallback callback) {
        if (mac == null || mac.split(":").length != 6) {
            throw new IllegalArgumentException("Illegal MAC ! ");
        }
        final BleGattCallback liteBleGattCallback = callback;
        final boolean z = autoConnect;
        startLeScanForMac(new PeriodMacScanCallback(mac,this, 12000) {
            public void onScanTimeout() {
                if (liteBleGattCallback != null) {
                    liteBleGattCallback.onConnectFailure(BleException.TIMEOUT_EXCEPTION);
                }
            }

            public void onDeviceFound(final BluetoothDevice device, int rssi, byte[] scanRecord) {
                BleDeviceManager.this.connect(device, z, liteBleGattCallback);
            }
        });
        return true;
    }

    /**
     * 获取当前连接gatt
     * @return
     */
    public BluetoothGatt getBluetoothGatt() {
        return this.bluetoothGatt;
    }

    /**
     * 初始化设备的服务
     */
    public void  discoverServices(){
        if(this.bluetoothGatt!=null) this.bluetoothGatt.discoverServices();
    }


    BleDataConnector bleDataConnector=null;
    /**
     * 获取当前连接设备的唯一数据操作对象
     * @return
     */
    public BleDataConnector getBleDataConnector() {
        if(bleDataConnector==null){
            bleDataConnector=new BleDataConnector(this);
        }
        return bleDataConnector ;
    }

    /**
     * 提供 据柄
     * @return
     */
    public Context getContext(){
        return context;
    }

    /**
     * 公用handler
     * @return
     */
    public Handler getMainHandler() {
        return this.mHanlder;
    }

    private class MyHanlder extends Handler {


        public MyHanlder(Looper looper) {
            super(looper);
        }


        public void handleMessage(Message msg) {
            BleCallback call = (BleCallback) msg.obj;
            if (call != null) {
                BleDeviceManager.this.removeGattCallback(call.getBluetoothGattCallback());
                call.onFailure(BleException.TIMEOUT_EXCEPTION);
            }
            msg.obj = null;
        }
    }

}
